/******************************************************************************
* This file is part of is32p218 platform,
* Copyright (c) 2009 HangZhou InfoStrong CO.,LTD. All rights reserved.
* This software may only be used under the terms of a valid, current,
* end user license from InfoStrong.
* Nothing else gives you the right to use this software.   
*
* Name:   host_if.c
* Desc:   Host communicaton interface C file
* Author: Jerry
* Date:   2009-10-26
* Note:   
* History:
*
******************************************************************************/
#include "xn5106x.h"
#include "drv_all.h"
#include "os_api.h"
#include "sys_glb.h"
#include "host_if.h"
#include "app.h"
#include "app_afn.h"
#include "drv_utils.h"

static void host_if_tsk( void *param );
static BOOL host_if_tmout_restart( HOST_IF_TMOUT_ID tmr_id, U32 tmout  );
static void host_if_tmout_proc( void *p_arg );


#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions

const U8 c_host_if_isdp_syn[HOST_IF_ISDP_STATE_SYN4+1] = 
{
	HOST_IF_ISDP_CHAR_SYN,
	HOST_IF_ISDP_CHAR_SYN2,
	HOST_IF_ISDP_CHAR_SYN3,
	HOST_IF_ISDP_CHAR_SYN4
};
#endif

static isOS_TCB g_host_tsk;
static isOS_STACK g_host_tsk_stack[TSK_STK_SIZE_HOST_IF];
HostIfCtrl g_host_if_ctrl;

const isOS_TskInfo c_hostif_tskinfo=
{
	host_if_tsk,					//-- task function
	NULL,							//-- task function parameter
	g_host_tsk_stack,				//-- task stack end addr in memory
	TSK_STK_SIZE_HOST_IF,			//-- task stack size (in isOS_S32,not bytes)
	"Host if task",					//-- task name
	TSK_PRIO_HOST_IF,				//-- task priority
};

#ifdef HOST_IF_TX_PREFIX
const U8 c_host_if_tx_prefix[4] = 
{
	0xFE, 0xFE, 0xFE, 0xFE
};
#endif
BOOL g_host_if_task_alive_flg = FALSE;
extern DrvUARTCtrl g_drv_uart_ctrl;

/****************************************************************************** 
                     Implementation
*******************************************************************************/
/*
* Function Name:
*   host_if_busy_set
* Description:
*   
* Parameters:
*   BOOL busy_flg:
* Returns:
* Author				Date 
*  Jerry				2009-11-26   
* Note:
*    
*/
S32 g_busy_cnt = 0;
void host_if_busy_set( BOOL busy_flg )
{
	// --- Set one PIN to indicat Busy
	if (busy_flg)
	{
		if ( 0 == g_busy_cnt )
		{
			drv_int_ena( INT_NUM_URXD, FALSE );
		}
		g_busy_cnt++;
	}
	else
	{
		if ( g_busy_cnt )
		{
			g_busy_cnt--;
			if ( 0== g_busy_cnt)
			{
				drv_int_ena( INT_NUM_URXD, TRUE );
			}
		}
	}
}

/*
* Function Name:
*   host_if_init
* Description:
*   Host communication interface initial
* Parameters:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2009-10-26   
* Note:
*    
*/
BOOL host_if_init( void )
{
	isOS_S32 ret;

	ret = isOS_TaskCreate( &g_host_tsk, \
						   &c_hostif_tskinfo,
						   OS_TASK_START_ON_CREATION
						   );
	if ( ret != pdPASS )
	{
		IS_ASSERT(0);
	}

	g_host_if_ctrl.m_rx_state = HOST_IF_STATE_SYN;
	g_host_if_ctrl.m_p_buff = NULL;
	g_host_if_ctrl.m_p_buff = (U8 *)sys_malloc( HOST_IF_PKG_BUFF_SIZE );
	if ( NULL ==g_host_if_ctrl.m_p_buff )
	{
		IS_ASSERT(0);
	}
#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
	g_host_if_ctrl.m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
#endif

	ret = isOS_TmrCreate( &g_host_if_ctrl.m_tmr, 1, host_if_tmout_proc, NULL, "Host IF Mon Timer" );
	if ( ret != pdPASS )
	{
		IS_ASSERT(0);
	}
	return TRUE;
}

/*
* Function Name:
*   host_if_cs_calc
* Description:
*   Verify CheckSum
* Parameters:
*   const U8 *p_data: Data pointer of checksum
*   U32 cs_len: Length
* Returns: 
*   U8: Checksum
* Author				Date 
*  Jerry				2009-10-27   
* Note:
*    Accumulate all data, igore C data
*/
U8 host_if_cs_calc( const U8 *p_data, U32 cs_len )
{
	U8 checksum = 0;
	// Verify CheckSum
	while (cs_len--)
	{
		checksum += *p_data++;
	}
	return checksum;
}

/*
* Function Name:
*   host_if_dlt_proc
* Description:
*   DL-T package procedure
* Parameters:
*   HostIfCtrl* p_if_ctrl:
*   U8 rec_byte:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2010-4-13   
* Note:
*    
*/
BOOL host_if_dlt_proc( HostIfCtrl *p_if_ctrl, U8 rec_byte )
{
	BOOL done_flg = FALSE;

#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
	if ( p_if_ctrl->m_isdp_rx_state>HOST_IF_ISDP_STATE_CTRL )	// IS-DP definitions
	{
		return FALSE;
	}
#endif
	/* Put Char to Buffer, in normal mode */
	while( FALSE == done_flg )
	{
		switch( p_if_ctrl->m_rx_state )
		{
		case HOST_IF_STATE_SYN:
			{
	#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
				if ( p_if_ctrl->m_isdp_rx_state > HOST_IF_ISDP_STATE_SYN )
				{	// should entry dlt package procedure
					done_flg = TRUE;
					break;
				}
	#endif
				if (HOST_IF_CHAR_SYN != rec_byte)
				{	// Error start SYN char
					p_if_ctrl->m_rx_len = 0;
				}
				else
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_MAC;
					p_if_ctrl->m_rx_len = 0;
					p_if_ctrl->m_mac_len = 0;
					p_if_ctrl->m_p_data = p_if_ctrl->m_p_buff;
					*p_if_ctrl->m_p_data++ = rec_byte;		// Whole frame, transparent
				}
				done_flg = TRUE;
				break;
			}
		case HOST_IF_STATE_MAC:
			{
				p_if_ctrl->m_mac_len++;
	
				if ( p_if_ctrl->m_mac_len>=HOST_IF_DLT_MAC_LEN )
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_SYN2;
				}
				done_flg = TRUE;
				break;
			}
		case HOST_IF_STATE_SYN2:
			{
				if (HOST_IF_CHAR_SYN != rec_byte)
				{	// Error start SYN2 char
					p_if_ctrl->m_rx_state = HOST_IF_STATE_SYN;
				}
				else
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_CTRL;
					done_flg = TRUE;
				}
				break;
			}
		case HOST_IF_STATE_CTRL:
			{
				p_if_ctrl->m_rx_state = HOST_IF_STATE_LEN;
				done_flg = TRUE;
				break;
			}
		case HOST_IF_STATE_LEN:
			{
				if ( rec_byte>HOST_IF_DLT_DATA_LEN )
				{
					p_if_ctrl->m_err_id = AFN_STATUS_ERR_LEN;
					p_if_ctrl->m_rx_state = HOST_IF_STATE_SYN;
				}
				else
				{
					if ( 0 == rec_byte )
					{	// No data region ,should change state to checksum
						p_if_ctrl->m_rx_len = HOST_IF_REC_DATA_LEN_OFFSET;
						p_if_ctrl->m_rx_state = HOST_IF_STATE_CHKSUM;
					}
					else
					{
						p_if_ctrl->m_rx_len = rec_byte+HOST_IF_REC_DATA_LEN_OFFSET;
						p_if_ctrl->m_rx_state = HOST_IF_STATE_DATA;
					}
					done_flg = TRUE;
				}
				break;
			}
	
		case HOST_IF_STATE_DATA:
			{
				if ( p_if_ctrl->m_p_data \
					 == (p_if_ctrl->m_p_buff+p_if_ctrl->m_rx_len) )
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_CHKSUM;
				}
				done_flg = TRUE;
				break;
			}
		case HOST_IF_STATE_CHKSUM:
			{
				if ( rec_byte == host_if_cs_calc( p_if_ctrl->m_p_buff,p_if_ctrl->m_rx_len ) )
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_END;
					done_flg = TRUE;
				}
				else
				{
					p_if_ctrl->m_err_id = AFN_STATUS_ERR_CS;
					p_if_ctrl->m_rx_state = HOST_IF_STATE_SYN;
				}
				break;
			}
		case HOST_IF_STATE_END:
			{
				if ( HOST_IF_CHAR_END == rec_byte )
				{
					p_if_ctrl->m_rx_len += HOST_IF_REC_TAIL_LEN_OFFSET;	// Should add checksum and end char
					done_flg = TRUE;
					return TRUE;
				}
				else
				{
					p_if_ctrl->m_rx_state = HOST_IF_STATE_SYN;
				}
				break;
			}
		default:
			{
				done_flg = TRUE;
				break;
			}
		}
	}
	return FALSE;
}

#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
/*
* Function Name:
*   host_if_isdp_proc
* Description:
*   Host IF IS-DP Procedure
* Parameters:
*   HostIfCtrl* p_if_ctrl:
*   U8 rec_byte:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2010-4-13   
* Note:
*    
*/
BOOL host_if_isdp_proc( HostIfCtrl *p_if_ctrl, U8 rec_byte )
{
	BOOL done_flg = FALSE;

	if ( p_if_ctrl->m_rx_state >= HOST_IF_STATE_CTRL )
	{
		return FALSE;
	}

	while( FALSE == done_flg )
	{
		switch( p_if_ctrl->m_isdp_rx_state )
		{
			case HOST_IF_ISDP_STATE_SYN:
			case HOST_IF_ISDP_STATE_SYN2:
			case HOST_IF_ISDP_STATE_SYN3:
			case HOST_IF_ISDP_STATE_SYN4:
			{
				if ( p_if_ctrl->m_rx_state > HOST_IF_STATE_SYN )
				{	// should entry dlt package procedure
					done_flg = TRUE;
					break;
				}
	
				if (c_host_if_isdp_syn[p_if_ctrl->m_isdp_rx_state] != rec_byte)
				{	// Error start SYN char
					if (HOST_IF_ISDP_STATE_SYN == p_if_ctrl->m_isdp_rx_state)
					{
						done_flg = TRUE;
					}
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
				}
				else
				{
					if ( HOST_IF_ISDP_STATE_SYN == p_if_ctrl->m_isdp_rx_state )
					{
						p_if_ctrl->m_rx_len = 0;
						p_if_ctrl->m_p_data= p_if_ctrl->m_p_buff;
						*p_if_ctrl->m_p_data++ = rec_byte;		// Whole frame, transparent
					}
					p_if_ctrl->m_isdp_rx_state++;
					done_flg = TRUE;
				}
				
				break;
			}
		case HOST_IF_ISDP_STATE_CTRL:
			{
				p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_LEN;
				done_flg = TRUE;
				break;
			}
		case HOST_IF_ISDP_STATE_LEN:
			{
				if ( rec_byte>HOST_IF_ISDP_DATA_LEN )
				{
					p_if_ctrl->m_err_id = AFN_STATUS_ERR_LEN;
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
				}
				else
				{
					if ( 0 == rec_byte )
					{	// No data region ,should change state to checksum
						p_if_ctrl->m_rx_len = HOST_IF_ISDP_DATA_LEN_OFFSET;
						p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_CHKSUM;
					}
					else
					{
						p_if_ctrl->m_rx_len = rec_byte+HOST_IF_ISDP_DATA_LEN_OFFSET;
						p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_DATA;
					}
					done_flg = TRUE;
				}
				break;
			}
	
		case HOST_IF_ISDP_STATE_DATA:
			{
				if ( p_if_ctrl->m_p_data \
					 == (p_if_ctrl->m_p_buff+p_if_ctrl->m_rx_len) )
				{
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_CHKSUM;
				}
				done_flg = TRUE;
				break;
			}
		case HOST_IF_ISDP_STATE_CHKSUM:
			{
				p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_CHKSUM2;
				done_flg = TRUE;
				break;
			}
		case HOST_IF_ISDP_STATE_CHKSUM2:
			{
				U16 crc16_in;
				crc16_in = ((U16)*(p_if_ctrl->m_p_data-1)<<8)+*(p_if_ctrl->m_p_data-2);
	
				if ( crc16_in == drv_utils_crc16(p_if_ctrl->m_p_buff,p_if_ctrl->m_rx_len) )
				{
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_END;
					done_flg = TRUE;
				}
				else
				{
					p_if_ctrl->m_err_id = AFN_STATUS_ERR_CS;
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
				}
				break;
			}
		case HOST_IF_ISDP_STATE_END:
			{
				if ( HOST_IF_ISDP_CHAR_END == rec_byte )
				{
					p_if_ctrl->m_rx_len += HOST_IF_ISDP_TAIL_LEN_OFFSET;
					done_flg = TRUE;
					return TRUE;
				}
				else
				{
					p_if_ctrl->m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
				}
				break;
			}
		default:
			{
				done_flg = TRUE;
				break;
			}
		}
	}
	return FALSE;
}
#endif
/*
* Function Name:
*   host_if_pkg_proc
* Description:
*   Host If package procedure
* Parameters:
*   U8 rec_byte:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2010-1-27   
* Note:
*   Frame format: 
*    85H+Seq(1B)+Ctrl(1B)+Len(2B, Big-end)+Data(nB)+CS(1B)+0AH
*  					  
*/
BOOL host_if_pkg_proc( HostIfCtrl *p_if_ctrl, U8 rec_byte )
{
	if ( NULL == p_if_ctrl->m_p_buff )
	{
		return FALSE;
	}
	p_if_ctrl->m_err_id = AFN_STATUE_ERR_OK;

#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
	if ( p_if_ctrl->m_rx_state>HOST_IF_STATE_SYN||p_if_ctrl->m_isdp_rx_state>HOST_IF_ISDP_STATE_SYN )
#else
	if ( p_if_ctrl->m_rx_state>HOST_IF_STATE_SYN )
#endif
	{
		*p_if_ctrl->m_p_data++ = rec_byte;		// Whole frame, transparent
	}


#ifdef HOST_IF_ISDP_FLG
	if ( p_if_ctrl->m_isdp_rx_state>HOST_IF_ISDP_STATE_SYN )
	{	// If IS-DP's state is not SYN, should call isdp_proc firstly.
		// --- IS-DP Procedure ----
		if ( host_if_isdp_proc(p_if_ctrl,rec_byte) )
		{
			return TRUE;
		}
		// --- DL-T Procedure
		if ( host_if_dlt_proc(p_if_ctrl,rec_byte) )
		{
			return TRUE;
		}
	}
	else
#endif	
	{	// Default: DL-T is high priority
		// --- DL-T Procedure
		if ( host_if_dlt_proc(p_if_ctrl,rec_byte) )
		{
			return TRUE;
		}
#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
		// --- IS-DP Procedure ----
		if ( host_if_isdp_proc(p_if_ctrl,rec_byte) )
		{
			return TRUE;
		}
#endif
	}
	return FALSE;
}



/*
* Function Name:
*   host_if_tmout_restart
* Description:
*   Time set
* Parameters:
*   HOST_IF_TMOUT_ID tmr_id: Timer ID
*   U32 tmout: Period value
* Returns: 
*   BOOL 
* Author				Date 
*  Jerry				2010-4-1   
* Note:
*    
*/
static BOOL host_if_tmout_restart( HOST_IF_TMOUT_ID tmr_id, U32 tmout  )
{
	tmr_id = tmr_id;
	if ( pdPASS != isOS_TmrSetExpireTick( &g_host_if_ctrl.m_tmr, (tmout/10)+1 ) )
	{
		IS_ASSERT(0);
		return FALSE;
	}
	isOS_TmrStart( &g_host_if_ctrl.m_tmr );
	return TRUE;
}
/*
* Function Name:
*   host_if_tmout_proc
* Description:
*   Host If receiving monitor timer
* Parameters:
*   void* p_arg:
* Returns:
* Author				Date 
*  Jerry				2010-4-1   
* Note:
*    
*/
static void host_if_tmout_proc( void *p_arg )
{
	p_arg = p_arg;
	{	// Reset receiving procedure state
		g_host_if_ctrl.m_rx_state = HOST_IF_STATE_SYN;
		g_host_if_ctrl.m_rx_len = 0;
#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
		g_host_if_ctrl.m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
#endif
	}
}

/*
* Function Name:
*   host_if_tsk
* Description:
*   Host Interface main task
* Parameters:
*   xCrHandle xHandle: co-routine handle
*   isOS_U32 uxIndex: cr's parameters
* Returns:
* Author				Date 
*  Jerry				2009-10-26   
* Note:
*    
*/
static void host_if_tsk( void *param )
{
	isOS_S32 result;
	MSG_HDR_HOST_T msg_hdr;
	isOS_U8 rec_byte;

	for(;;)
	{
		result = isOS_QueueReceive( drv_uart_que_get(DRV_UART_QUE_RX), &msg_hdr,  \
							   TM_WAIT_FOREVER );
		drv_sys_wdt_feed();
		if (pdPASS == result )
		{	// return Seccess
			if ( msg_hdr.m_msg_id == MSG_IDLE_TO_HOST_IF_CHECK )
			{	// Data region is validate, data from pointer of m_pointer
				g_host_if_task_alive_flg = TRUE;
			}
			else
			{
				rec_byte = msg_hdr.m_rec_byte;
				if ( NULL == g_host_if_ctrl.m_p_buff )
				{
					g_host_if_ctrl.m_p_buff = (U8 *)sys_malloc( HOST_IF_PKG_BUFF_SIZE );
					if ( NULL ==g_host_if_ctrl.m_p_buff )
					{
						IS_ASSERT(0);
					}
				}
				drv_uart_busy_set( FALSE );		// Release Busy status
				if ( host_if_pkg_proc( &g_host_if_ctrl, rec_byte) )
				{	// Host Interface Data Message
					isOS_TmrStop( &g_host_if_ctrl.m_tmr );		// Stop timer
					// @@@@@@new000005 jerry, on 2011-5-27 --- begin
					// Host2app message number limit
					if ( app_host2afn_msg_num_inc() )
					// @@@@@@new000005 jerry, on 2011-5-27 --- end
					{
						if ( FALSE == app_msg_snd( MSG_HOSTIF_TO_APP_DATA, g_host_if_ctrl.m_p_buff, \
												   g_host_if_ctrl.m_rx_len ) )
						{	// Don't free this buffer
							//Send message failed,should dec host counter num,2015-03-17 skyw modify
							extern void app_afn_msg_num_dec( void );
							app_afn_msg_num_dec();
							IS_ASSERT(0);
						}
						else
						{	// Get new memory buffer
							g_host_if_ctrl.m_p_buff = NULL;
						}
					}
					g_host_if_ctrl.m_p_data = g_host_if_ctrl.m_p_buff;
					g_host_if_ctrl.m_rx_state = HOST_IF_STATE_SYN;
				#ifdef HOST_IF_ISDP_FLG			// IS-DP definitions
					g_host_if_ctrl.m_isdp_rx_state = HOST_IF_ISDP_STATE_SYN;
				#endif
				}
				else
				{	// Error procedure
					host_if_tmout_restart( HOST_IF_TMOUT_REC, HOST_IF_TMOUT_REC_VAL );
				}
			}
		}
	} 
}
BOOL host_if_msg_snd( U8 msg_id, U8 p_msg_data )
{
	MSG_HDR_HOST_T msg_hdr;
	msg_hdr.m_msg_id = msg_id;
	msg_hdr.m_rec_byte = p_msg_data;
	if ( pdPASS !=isOS_QueueSend( &g_drv_uart_ctrl.m_rx_que, &msg_hdr, TM_POLLING ) )
	{
		IS_ASSERT(0);
		return FALSE;
	}
	return TRUE;
}
void host_if_msg_snd_alive_check(void)
{
	host_if_msg_snd(MSG_IDLE_TO_HOST_IF_CHECK,0);		// to app_main_tsk
}
/*
* Function Name:
*   host_if_send
* Description:
*   
* Parameters:
*   U8* p_snd_data:
*   U32 snd_len:
* Returns:
*   BOOL:
* Author				Date 
*  Jerry				2010-4-13   
* Note:
*    
*/
BOOL host_if_send( U8 *p_snd_data, U32 snd_len )
{
#ifdef HOST_IF_TX_PREFIX
	drv_uart_send( (U8*)c_host_if_tx_prefix, sizeof(c_host_if_tx_prefix), TRUE );
#endif
	return drv_uart_send( p_snd_data, snd_len, TRUE );
}

/*
* Function Name:
*   host_if_tx_buff_get
* Description:
*   Host IF TX buffer
* Parameters:
* Returns:
*   U8*:
* Author				Date 
*  Jerry				2009-11-27   
* Note:
*    
*/
U8 *host_if_tx_buff_get( void )
{
	//return g_host_if_ctrl.m_tx_buff;
	return NULL;
}

